home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / appmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-21  |  7.8 KB  |  338 lines

  1. /* appmenu.c- application defined menu
  2.  *
  3.  *  Window Maker window manager
  4.  * 
  5.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  6.  * 
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. #include "wconfig.h"
  24.  
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #include <X11/Xproto.h>
  28. #include <X11/Xatom.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <unistd.h>
  33.  
  34. #include "WindowMaker.h"
  35. #include "wcore.h"
  36. #include "menu.h"
  37. #include "actions.h"
  38. #include "funcs.h"
  39.  
  40. #include "framewin.h"
  41.  
  42.  
  43. /******** Global Variables **********/
  44. extern Atom _XA_WINDOWMAKER_MENU;
  45. extern Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
  46. extern Time LastTimestamp;
  47.  
  48. extern WPreferences wPreferences;
  49.  
  50. typedef struct {
  51.     short code;
  52.     short tag;
  53.     Window window;
  54. } WAppMenuData;
  55.  
  56.  
  57.  
  58. enum {
  59.     wmBeginMenu = 1,
  60.       wmEndMenu = 2,
  61.       wmNormalItem = 10,
  62.       wmDoubleItem = 11,
  63.       wmSubmenuItem = 12
  64. };
  65.  
  66. enum {
  67.     wmSelectItem = 1
  68. };
  69.  
  70.  
  71. static void
  72. sendMessage(Window window, int what, int tag)
  73. {
  74.     XEvent event;
  75.  
  76.     event.xclient.type = ClientMessage;
  77.     event.xclient.message_type = _XA_WINDOWMAKER_MENU;
  78.     event.xclient.format = 32;
  79.     event.xclient.display = dpy;
  80.     event.xclient.window = window;
  81.     event.xclient.data.l[0] = LastTimestamp;
  82.     event.xclient.data.l[1] = what;
  83.     event.xclient.data.l[2] = tag;
  84.     event.xclient.data.l[3] = 0;
  85.     XSendEvent(dpy, window, False, NoEventMask, &event);
  86.     XFlush(dpy);
  87. }
  88.  
  89.  
  90. static void 
  91. notifyClient(WMenu *menu, WMenuEntry *entry)
  92. {
  93.     WAppMenuData *data = entry->clientdata;
  94.     
  95.     sendMessage(data->window, wmSelectItem, data->tag);
  96. }
  97.  
  98.  
  99.  
  100. static WMenu*
  101. parseMenuCommand(WScreen *scr, Window win, char **slist, int count, int *index)
  102. {
  103.     WMenu *menu;
  104.     int command;
  105.     int code, pos;
  106.     char title[300];
  107.     char rtext[300];
  108.  
  109.     if (strlen(slist[*index])>300) {
  110.     wwarning("appmenu: menu command size exceeded in window %x", win);
  111.     return NULL;
  112.     }
  113.     if (sscanf(slist[*index], "%i %i %n", &command, &code, &pos)<2
  114.     || command!=wmBeginMenu) {
  115.     wwarning("appmenu: bad menu entry \"%s\" in window %x",
  116.          slist[*index], win);
  117.     return NULL;
  118.     }
  119.     strcpy(title, &slist[*index][pos]);
  120.     menu = wMenuCreateForApp(scr, title, *index==1);
  121.     if (!menu)
  122.       return NULL;
  123.     *index += 1;
  124.     while (*index<count) {
  125.     int ecode, etag, enab;
  126.  
  127.     if (sscanf(slist[*index], "%i", &command)!=1) {
  128.         wMenuDestroy(menu, True);
  129.         wwarning("appmenu: bad menu entry \"%s\" in window %x", 
  130.              slist[*index], win);
  131.         return NULL;
  132.     }
  133.     
  134.     if (command==wmEndMenu) {
  135.         *index += 1;
  136.         break;
  137.         
  138.     } else if (command==wmNormalItem
  139.            || command==wmDoubleItem) {
  140.         WAppMenuData *data;
  141.         WMenuEntry *entry;
  142.  
  143.         if (command == wmNormalItem) {
  144.         if (sscanf(slist[*index], "%i %i %i %i %n",
  145.                &command, &ecode, &etag, &enab, &pos)!=4
  146.             || ecode!=code) {
  147.             wMenuDestroy(menu, True);
  148.             wwarning("appmenu: bad menu entry \"%s\" in window %x", 
  149.                  slist[*index], win);
  150.             return NULL;
  151.         }
  152.         strcpy(title, &slist[*index][pos]);
  153.         rtext[0] = 0;
  154.         } else {
  155.         if (sscanf(slist[*index], "%i %i %i %i %s %n",
  156.                &command, &ecode, &etag, &enab, rtext, &pos)!=5
  157.             || ecode!=code) {
  158.             wMenuDestroy(menu, True);
  159.             wwarning("appmenu: bad menu entry \"%s\" in window %x", 
  160.                  slist[*index], win);
  161.             return NULL;
  162.         }
  163.         strcpy(title, &slist[*index][pos]);
  164.         }
  165.         if (!(data = malloc(sizeof(WAppMenuData)))) {
  166.         wwarning("appmenu: out of memory making menu for window %x",
  167.              win);
  168.         wMenuDestroy(menu, True);
  169.         return NULL;
  170.         }
  171.         data->code = code;
  172.         data->tag = etag;
  173.         data->window = win;
  174.         entry = wMenuAddCallback(menu, title, notifyClient, data);
  175.         if (!entry) {
  176.         wMenuDestroy(menu, True);
  177.         wwarning("appmenu: out of memory creating menu for window %x",
  178.              slist[*index], win);
  179.         free(data);
  180.         return NULL;
  181.         }
  182.         if (rtext[0]!=0)
  183.           entry->rtext = wstrdup(rtext);
  184.         else
  185.           entry->rtext = NULL;
  186.         entry->free_cdata = free;
  187.         *index += 1;
  188.  
  189.     } else if (command==wmSubmenuItem) {
  190.         int ncode;
  191.         WMenuEntry *entry;
  192.         WMenu *submenu;
  193.  
  194.         if (sscanf(slist[*index], "%i %i %i %i %i %n",
  195.                &command, &ecode, &etag, &enab, &ncode, &pos)!=5
  196.         || ecode!=code) {
  197.         wMenuDestroy(menu, True);
  198.         wwarning("appmenu: bad menu entry \"%s\" in window %x", 
  199.              slist[*index], win);
  200.  
  201.         return NULL;
  202.         }
  203.         strcpy(title, &slist[*index][pos]);
  204.         *index += 1;
  205.  
  206.         submenu = parseMenuCommand(scr, win, slist, count, index);
  207.  
  208.         entry = wMenuAddCallback(menu, title, NULL, NULL);
  209.         
  210.         if (!entry) {
  211.         wMenuDestroy(menu, True);
  212.         wMenuDestroy(submenu, True);
  213.         wwarning("appmenu: out of memory creating menu for window %x",
  214.              slist[*index], win);
  215.         return NULL;
  216.         }
  217.  
  218.         wMenuEntrySetCascade(menu, entry, submenu);
  219.         
  220.     } else {
  221.         wMenuDestroy(menu, True);
  222.         wwarning("appmenu: bad menu entry \"%s\" in window %x", 
  223.              slist[*index], win);
  224.         return NULL;
  225.     }
  226.     }    
  227.  
  228.     return menu;
  229. }
  230.  
  231.  
  232. WMenu*
  233. wAppMenuGet(WScreen *scr, Window window)
  234. {
  235.     XTextProperty text_prop;
  236.     int count, i;
  237.     char **slist;
  238.     WMenu *menu;
  239.     
  240.     if (!XGetTextProperty(dpy, window, &text_prop, _XA_WINDOWMAKER_MENU)) {
  241.     return NULL;
  242.     }
  243.     if (!XTextPropertyToStringList(&text_prop, &slist, &count) || count<1) {
  244.     XFree(text_prop.value);
  245.     return NULL;
  246.     }
  247.     XFree(text_prop.value);
  248.     if (strcmp(slist[0], "WMMenu 0")!=0) {
  249.     wwarning("appmenu: unknown version of WMMenu in window %x: %s",
  250.          window,  slist[0]);
  251.     XFreeStringList(slist);
  252.     return NULL;
  253.     }
  254.  
  255.     i = 1;
  256.     menu = parseMenuCommand(scr, window, slist, count, &i);
  257.     if (menu)
  258.       menu->parent = NULL;
  259.     
  260.     XFreeStringList(slist);
  261.  
  262.     return menu;
  263. }
  264.  
  265. void
  266. wAppMenuDestroy(WMenu *menu) 
  267. {
  268.     if (menu)
  269.       wMenuDestroy(menu, True);
  270. }
  271.  
  272.  
  273. static void
  274. mapmenus(WMenu *menu)
  275. {
  276.     int i;
  277.  
  278.     if (menu->flags.mapped)
  279.       XMapWindow(dpy, menu->frame->core->window);
  280.     if (menu->brother->flags.mapped)
  281.       XMapWindow(dpy, menu->brother->frame->core->window);
  282.     for (i=0; i<menu->cascade_no; i++) {
  283.     if (menu->cascades[i])
  284.       mapmenus(menu->cascades[i]);
  285.     }
  286. }
  287.  
  288.  
  289. void
  290. wAppMenuMap(WMenu *menu, WWindow *wwin)
  291. {
  292.  
  293.     if (!menu)
  294.       return;
  295.     
  296.     if (!menu->flags.mapped) {
  297.     wMenuMap(menu);
  298.     }
  299.     if(wwin && (wPreferences.focus_mode!=WKF_CLICK)) {
  300.     int x, min;
  301.  
  302.         min = 20; /* Keep at least 20 pixels visible */
  303.     if( wwin->frame_x > min ) {
  304.         x = wwin->frame_x - menu->frame->core->width;
  305.     }
  306.     else {
  307.         x = min - menu->frame->core->width;
  308.     }
  309.     wMenuMove(menu, x, wwin->frame_y, True);
  310.     }
  311.     mapmenus(menu);
  312.     
  313. }
  314.  
  315.  
  316. static void
  317. unmapmenus(WMenu *menu)
  318. {
  319.     int i;
  320.     
  321.     if (menu->flags.mapped)
  322.       XUnmapWindow(dpy, menu->frame->core->window);
  323.     if (menu->brother->flags.mapped)
  324.       XUnmapWindow(dpy, menu->brother->frame->core->window);
  325.     for (i=0; i<menu->cascade_no; i++) {
  326.     if (menu->cascades[i])
  327.       unmapmenus(menu->cascades[i]);
  328.     }
  329. }
  330.  
  331. void
  332. wAppMenuUnmap(WMenu *menu)
  333. {
  334.     if (menu)
  335.       unmapmenus(menu);
  336. }
  337.  
  338.